package org.truenewx.tnxjee.repo.mybatis.mapper;

import java.io.Serializable;
import java.util.List;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.truenewx.tnxjee.core.util.CollectionUtil;
import org.truenewx.tnxjee.core.util.tuple.Binate;
import org.truenewx.tnxjee.model.entity.relation.Relation;
import org.truenewx.tnxjee.model.entity.relation.RelationKey;

public interface RelationMapper<T extends Relation<L, R>, L extends Serializable, R extends Serializable>
        extends EntityMapper<T> {

    @Override
    default int save(T relation) {
        L leftId = relation.getLeftId();
        R rightId = relation.getRightId();
        // 当左标识和右标识中有一个为引用实体的标识时，子Mapper需自行实现update和insert方法，否则会报引用属性没有对应的TypeHandler的问题
        if (existsById(leftId, rightId)) {
            return update(relation, getIdQueryWrapper(leftId, rightId));
        } else {
            return insert(relation);
        }
    }

    /**
     * @return 标识列名组，左元为左标识列名，右元为右标识列名
     */
    default Binate<String, String> getIdColumnName() {
        throw new UnsupportedOperationException(getClass().getName() + " does not implement method getIdColumnName()");
    }

    default QueryWrapper<T> getIdQueryWrapper(L leftId, R rightId) {
        Binate<String, String> idColumnName = getIdColumnName();
        return new QueryWrapper<T>().eq(idColumnName.getLeft(), leftId).eq(idColumnName.getRight(), rightId);
    }

    default boolean existsById(L leftId, R rightId) {
        return exists(getIdQueryWrapper(leftId, rightId));
    }

    @SuppressWarnings("unchecked")
    default T selectById(L leftId, R rightId) {
        List<Object> list = selectObjs(getIdQueryWrapper(leftId, rightId));
        return (T) CollectionUtil.getFirst(list);
    }

    default int deleteById(L leftId, R rightId) {
        return delete(getIdQueryWrapper(leftId, rightId));
    }

    @Override
    @SuppressWarnings("unchecked")
    default T selectById(Serializable id) {
        RelationKey<L, R> key = (RelationKey<L, R>) id;
        return selectById(key.getLeft(), key.getRight());
    }

    @Override
    @SuppressWarnings("unchecked")
    default int deleteById(Serializable id) {
        RelationKey<L, R> key = (RelationKey<L, R>) id;
        return deleteById(key.getLeft(), key.getRight());
    }

}
